\defmodule{RandomVariateGenWithCache}

This class represents a random variate generator whose values
are cached for more efficiency when using
common random numbers.  An object
from this class is constructed with a reference to a
\class{RandomVariateGen} instance used to
get the random numbers.  These numbers
are stored in an internal array to be retrieved later.
The dimension of the array increases as the values
are generated.
If the \method{nextDouble}{()} method is called after
the object is reset (by calling 
\method{setCachedValues}{(DoubleArrayList)}), it gives back the cached
values instead of computing new ones.
If the cache is exhausted before the generator is reset,
new values are computed and added to the cache.

Such caching allows for a better performance with
common random numbers, when
generating random variates is time-consuming.
However, using such caching may lead to memory problems if
a large quantity of random numbers are needed.

\bigskip\hrule

\begin{code}
\begin{hide}
/*
 * Class:        RandomVariateGenWithCache
 * Description:  random variate generator whose values are cached for efficiency
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Universite de Montreal
 * Organization: DIRO, Universite de Montreal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * A copy of the GNU General Public License is available at
   <a href="http://www.gnu.org/licenses">GPL licence site</a>.
 */
\end{hide}
package umontreal.iro.lecuyer.randvar;\begin{hide}

import umontreal.iro.lecuyer.randvar.RandomVariateGen;
import cern.colt.list.DoubleArrayList;
import umontreal.iro.lecuyer.rng.RandomStream;
import umontreal.iro.lecuyer.probdist.Distribution;
\end{hide}

public class RandomVariateGenWithCache extends RandomVariateGen\begin{hide} {
   private RandomVariateGen rvg;
   private DoubleArrayList values;
   private int index = 0;
   private boolean caching = true;
\end{hide}
\end{code}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection* {Constructors}
\begin{code}

   public RandomVariateGenWithCache (RandomVariateGen rvg)\begin{hide} {
      if (rvg == null)
         throw new NullPointerException
            ("The given random variate generator cannot be null");
      this.rvg = rvg;
      values = new DoubleArrayList();
   }\end{hide}
\end{code}
\begin{tabb}   Constructs a new cached random variate generator with
 internal generator \texttt{rvg}.
\end{tabb}
\begin{htmlonly}
   \param{rvg}{the random variate generator whose values are cached.}
   \exception{NullPointerException}{if \texttt{rvg} is \texttt{null}.}
\end{htmlonly}
\begin{code}

   public RandomVariateGenWithCache (RandomVariateGen rvg,
                                     int initialCapacity)\begin{hide} {
      if (rvg == null)
         throw new NullPointerException
            ("The given random variate generator cannot be null");
      this.rvg = rvg;
      values = new DoubleArrayList (initialCapacity);
   }\end{hide}
\end{code}
\begin{tabb}   Constructs a new cached random variate generator
 with internal generator \texttt{rvg}.  The \texttt{initialCapacity}
 parameter is used to set the initial capacity of the internal array
 which can grow as needed; it does not limit the maximal
 number of cached values.
\end{tabb}
\begin{htmlonly}
   \param{rvg}{the random variate generator whose values are cached.}
   \param{initialCapacity}{the number of cached values.}
   \exception{NullPointerException}{if \texttt{rvg} is \texttt{null}.}
\end{htmlonly}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection* {Methods}
\begin{code}

   public boolean isCaching()\begin{hide} {
      return caching;
   }\end{hide}
\end{code}
\begin{tabb}   Determines if the random variate generator is caching values,
 default being \texttt{true}.
 When caching is turned OFF, the \method{nextDouble}{()}
 method simply calls the corresponding method on the internal
 random variate generator, without storing the generated values.
\end{tabb}
\begin{htmlonly}
   \return{the caching indicator.}
\end{htmlonly}
\begin{code}

   public void setCaching (boolean caching)\begin{hide} {
      if (this.caching && !caching)
         clearCache();
      this.caching = caching;
   }\end{hide}
\end{code}
\begin{tabb}   Sets the caching indicator to \texttt{caching}.
 If caching is turned OFF, this method calls \method{clearCache}{()}
 to clear the cached values.
\end{tabb}
\begin{htmlonly}
   \param{caching}{the new value of the caching indicator.}
\end{htmlonly}
\begin{code}

   public RandomVariateGen getCachedGen()\begin{hide} {
      return rvg;
   }\end{hide}
\end{code}
\begin{tabb}   Returns a reference to the random variate generator
 whose values are cached.
\end{tabb}
\begin{htmlonly}
   \return{a reference to the random variate generator whose values are cached.}
\end{htmlonly}
\begin{code}

   public void setCachedGen (RandomVariateGen rvg)\begin{hide} {
      if (rvg == null)
         throw new NullPointerException
            ("The given random variate generator cannot be null");
      if (rvg == this.rvg)
         return;
      this.rvg = rvg;
      clearCache();
   }\end{hide}
\end{code}
\begin{tabb}   Sets the random variate generator whose values are cached to
 \texttt{rvg}.  If the generator is changed, the \method{clearCache}{()}
 method is called.
\end{tabb}
\begin{htmlonly}
   \param{rvg}{the new random variate generator whose values are cached.}
   \exception{NullPointerException}{if \texttt{rvg} is \texttt{null}.}
\end{htmlonly}
\begin{code}

   public void clearCache()\begin{hide} {
      //values.clear();
      // Keep the array previously returned by getCachedValues
      // intact to allow caching values for several
      // replications.
      values = new DoubleArrayList();
      index = 0;
   }\end{hide}
\end{code}
\begin{tabb}   Clears the cached values for this cached generator.
 Any subsequent call will then obtain new values
 from the internal generator.
\end{tabb}
\begin{code}

   public void initCache()\begin{hide} {
      index = 0;
   }\end{hide}
\end{code}
\begin{tabb}   Resets this generator to recover values from the cache.
 Subsequent calls
 to \method{nextDouble}{()} will return the cached random
 values until all the values are returned.  When the array
 of cached values is exhausted, the internal random variate
 generator is used to generate new values which are added
 to the internal array as well.
 This method is equivalent to calling \method{setCacheIndex}{(int)}.
\end{tabb}
\begin{code}

   public int getNumCachedValues()\begin{hide} {
      return values.size();
   }\end{hide}
\end{code}
\begin{tabb}   Returns the total number of values cached by this generator.
\end{tabb}
\begin{htmlonly}
   \return{the total number of cached values.}
\end{htmlonly}
\begin{code}

   public int getCacheIndex()\begin{hide} {
      return index;
   }\end{hide}
\end{code}
\begin{tabb}   Return the index of the next cached value that will be
 returned by the generator.
 If the cache is exhausted, the 
 returned value corresponds to the value returned by
 \method{getNumCachedValues}{()}, and a subsequent call to
 \method{nextDouble}{()} will generate a new variate rather than
 reading a previous one from the cache.
 If caching is disabled, this always returns 0.
\end{tabb}
\begin{htmlonly}
   \return{the index of the next cached value.}
\end{htmlonly}
\begin{code}

   public void setCacheIndex (int newIndex)\begin{hide} {
      if (newIndex < 0 || newIndex > values.size())
         throw new IllegalArgumentException
         ("newIndex must not be negative or greater than the cache size");
      index = newIndex;
   }\end{hide}
\end{code}
\begin{tabb}   Sets the index, in the cache, of the next value returned
 by \method{nextDouble}{()}.
 If \texttt{newIndex} is 0, this is equivalent to
 calling \method{initCache}{()}.
 If \texttt{newIndex} is \method{getNumCachedValues}{()},
 subsequent calls to \method{nextDouble}{()} will add
 new values to the cache.
\end{tabb}
\begin{htmlonly}
   \param{newIndex}{the new index.}
   \exception{IllegalArgumentException}{if \texttt{newIndex}
 is negative or greater than or equal to the cache size.}
\end{htmlonly}
\begin{code}

   public DoubleArrayList getCachedValues()\begin{hide} {
      return values;
   }\end{hide}
\end{code}
\begin{tabb}   Returns an array list containing the values
 cached by this random variate generator.
\end{tabb}
\begin{htmlonly}
   \return{the array of cached values.}
\end{htmlonly}
\begin{code}

   public void setCachedValues (DoubleArrayList values)\begin{hide} {
      if (values == null)
         throw new NullPointerException();
      this.values = values;
      index = values.size();
   }\end{hide}
\end{code}
\begin{tabb}   Sets the array list containing the cached
 values to \texttt{values}.
 This resets the cache index to
 the size of the given array.
\end{tabb}
\begin{htmlonly}
   \param{values}{the array list of cached values.}
   \exception{NullPointerException}{if \texttt{values} is \texttt{null}.}
\end{htmlonly}
\begin{code}\begin{hide}

   public double nextDouble() {
      if (!caching)
         return rvg.nextDouble();
      else if (index >= values.size()) {
         double v = rvg.nextDouble();
         values.add (v);
         ++index;
         return v;
      }
      else
         return values.getQuick (index++);
   }

   public void nextArrayOfDouble (double[] v, int start, int n) {
      if (!caching) {
         rvg.nextArrayOfDouble (v, start, n);
         return;
      }
      int remainingValues = values.size() - index;
      if (remainingValues < 0)
         remainingValues = 0;
      int ncpy = Math.min (n, remainingValues);
      if (ncpy > 0) {
         System.arraycopy (values.elements(), index, v, start, ncpy);
         index += ncpy;
      }
      int ngen = n - ncpy;
      if (ngen > 0) {
         rvg.nextArrayOfDouble (v, start + ncpy, ngen);
         for (int i = ncpy; i < n; i++) {
            values.add (v[start + i]);
            ++index;
         }
      }
   }

   public RandomStream getStream() {
      return rvg.getStream();
   }

   public Distribution getDistribution() {
      return rvg.getDistribution();
   }
}\end{hide}
\end{code}
